//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Apache License, Version 2.0.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************

namespace Microsoft.Research.ScientificWorkflow.ManagementStudioControls.RegistryManagerModule
{
    using System.Windows;
    using ManagementStudioServices.Interfaces;
    using Microsoft.Research.ScientificWorkflow.ManagementStudioModels;
    using Microsoft.Research.ScientificWorkflow.TridentUtilities;
    using Microsoft.Practices.Unity;
    using SR = Microsoft.Research.DataLayer;
    using System.Collections.ObjectModel;
    using System.Linq;
    using System.Collections.Generic;
    using Microsoft.Research.ScientificWorkflow.TridentModel;
    using Microsoft.Research.eResearch.Common.Linq;
    using Microsoft.Research.DataLayer;
    using System;

    /// <summary>
    /// The presenter for the left pane workflow tree.
    /// </summary>
    public class WorkflowLeftPanePresenter : RegistryManagerLeftPaneItemPresenterBase
    {
        /// <summary>
        /// Gets or sets the root model.
        /// </summary>
        /// <value>The root model.</value>
        public override BaseRegMgrModel RootModel
        {
            get;
            set;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="WorkflowLeftPanePresenter"/> class.
        /// </summary>
        /// <param name="container">The container.</param>
        /// <param name="leftPane">The left pane.</param>
        /// <param name="service">The service.</param>
        public WorkflowLeftPanePresenter(IUnityContainer container, WorkflowTree leftPane, IRegistryManagerService service)
            : base(container, service)
        {
            this.LeftPaneView = leftPane;
            leftPane.Model = this;
        }

        #region IRegistryManagerLeftPaneItemPresenter Members

        /// <summary>
        /// Gets or sets the search view.
        /// </summary>
        /// <value>The search view.</value>
        public override UIElement SearchView
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the left pane view.
        /// </summary>
        /// <value>The left pane view.</value>
        public override UIElement LeftPaneView
        {
            get;
            set;
        }

        /// <summary>
        /// Initializes this instance.
        /// </summary>
        public override void Initialize()
        {
            try
            {
                if (this.LeftPaneTreeItems.Count > 0)
                {
                    this.LeftPaneTreeItems.Clear();
                }

                this.BuildTree();
            }
            catch (TridentCustomException ex)
            {
                TridentErrorHandler.HandleTridentCustomExceptionInUI(ex);
            }
            catch (Exception ex)
            {
                TridentErrorHandler.HandleKnownExceptionsInUI(ex);                
            }            
        }

        #endregion

        private void BuildTree()
        {
            SR.SystemPolicy policy = this.RegistryManagerService.GetSystemPolicy();
            SR.Namespace workflowRoot = this.RegistryManagerService.GetWorkflowCategories();
            CategoryViewModel workflowRootModel = new CategoryViewModel(workflowRoot, null, CategoryType.Workflow, policy, true);
            Collection<SR.Namespace> categories = new Collection<SR.Namespace>();
            this.RegistryManagerService.GetMyWorkflowsForCurrentUser(categories);
            categories.ForEach(category => workflowRootModel.Children.Add(new CategoryViewModel(category, workflowRootModel, CategoryType.Workflow, policy, false)));

            if (TridentAuthentication.LoggedUserRole == UserRole.Admin)
            {
                categories.Clear();
                this.RegistryManagerService.GetAllUsersMyWorkflows(categories);
                if (categories.Count > 0 && categories.Any(category => category.Activitys.Where(activity => !activity.IsDeleted).Count() > 0))
                {
                    CategoryViewModel allUsersWorkflowsModel = CategoryViewModel.GenerateVirtualCategoryModel("All users' Workflows", workflowRootModel, new List<Activity>(), CategoryType.Workflow, Guid.Empty, policy);
                    foreach (SR.Namespace category in categories)
                    {
                        if (category.Activitys.Where(activity => !activity.IsDeleted).Count() > 0)
                        {
                            Guid categoryGuid = Guid.Empty;
                            if (category.Activitys[0].Namespaces.Count > 0)
                            {
                                categoryGuid = (category.Activitys[0].Namespaces[0] as IObject).ID;
                            }

                            CategoryViewModel catModel = CategoryViewModel.GenerateVirtualCategoryModel((new SecurityPrincipalModel(category.User as ISecurityPrincipal)).DisplayName, allUsersWorkflowsModel, category.Activitys, CategoryType.Workflow, categoryGuid, policy);
                            allUsersWorkflowsModel.Children.Add(catModel);
                        }
                    }

                    workflowRootModel.Children.Add(allUsersWorkflowsModel);
                    workflowRootModel.ChildCategories.Add(allUsersWorkflowsModel);
                }
            }
            else if (TridentAuthentication.LoggedUserRole == UserRole.NormalUser)
            {
                Collection<Activity> sharedWorkflows = this.RegistryManagerService.GetAllSharedWorkflowsForCurrentUser();
                if (sharedWorkflows != null && sharedWorkflows.Count > 0)
                {
                    CategoryViewModel sharedWfsCategory = CategoryViewModel.GenerateVirtualCategoryModel("Shared Workflows", workflowRootModel, new List<Activity>(), CategoryType.Workflow, Guid.Empty, policy);
                    var userGroupedWfs = from wf in sharedWorkflows
                                         group wf by (wf.Owner as IObject).ID into wfGroup
                                         select new
                                         {
                                             SecurityPrincipal = new SecurityPrincipalModel(wfGroup.ElementAt(0).Owner),
                                             UserSharedWfs = wfGroup.Where(wf => this.CheckForActivity(wf))
                                         };

                    if (userGroupedWfs != null && userGroupedWfs.Count() > 0)
                    {
                        var groupedNonEmpty = userGroupedWfs.Where(userGrp => userGrp.UserSharedWfs != null && userGrp.UserSharedWfs.Count() > 0);
                        groupedNonEmpty.ForEach(userGroup => sharedWfsCategory.Children.Add(CategoryViewModel.GenerateVirtualCategoryModel(userGroup.SecurityPrincipal.DisplayName, sharedWfsCategory, userGroup.UserSharedWfs, CategoryType.Workflow, this.FetchCategoryId(userGroup.UserSharedWfs.ElementAt(0)), policy)));
                    }

                    workflowRootModel.Children.Add(sharedWfsCategory);
                    workflowRootModel.ChildCategories.Add(sharedWfsCategory);
                }
            }

            this.LeftPaneTreeItems.Add(workflowRootModel);
            this.RootModel = workflowRootModel;                   
        }

        private bool CheckForActivity(Activity activity)
        {
            bool validActivity = false;
            if (activity != null && activity.Namespaces != null && activity.Namespaces.Count > 0)
            {
                if (!activity.IsDeleted
                    && activity.Namespaces[0].Name.Equals("My Workflow", StringComparison.OrdinalIgnoreCase)
                    && activity.Namespaces[0].Parent.Name.Equals("UserWorkflowRoot", StringComparison.OrdinalIgnoreCase)
                    && (!string.IsNullOrEmpty(activity.VersionLabel) || activity.IsLatestVersion())
                    && activity.Security.Rights.AuthorWorkflow.Check(TridentAuthentication.LoggedInUser))
                {
                    validActivity = true;
                }
            }

            return validActivity;
        }

        private Guid FetchCategoryId(Activity activity)
        {
            Guid id = Guid.Empty;
            if (activity.Namespaces.Count > 0)
            {
                id = (activity.Namespaces[0] as IObject).ID;
            }

            return id;
        }
    }
}
